package com.webchat.common.enums;

/**
 * LUA 脚本常量池
 */
public class LUAScriptConstants {


    /**
     * 库存扣减LUA脚本
     * -------------------------------------
     * LUA脚本执行返回：
     *      -2: 代表缓存不存在
     *      -1: 库存在执行后将被扣除为负数
     *      0:  更新失败
     *      1:  库存更新成功
     */
    public static final String UPDATE_SKU_STOCK_LUA =
            """
                local stockCacheKey = KEYS[1]
                local skuId = ARGV[1]
                local num = tonumber(ARGV[2])
                local existRes = tonumber(redis.call('HEXISTS', stockCacheKey, skuId) or '0')
                if existRes == 0 then
                   return '-2'
                end
                local stock = tonumber(redis.call('HGET', stockCacheKey, skuId))
                if stock == nil then
                   return '-1'
                end
                local preUpdateRes = stock + num
                if preUpdateRes < 0 then
                   return '-1'
                end
                redis.call('HSET', stockCacheKey, skuId, preUpdateRes)
                return '1'
            """;


    /**
     * IM 发红包脚本
     */
    public static final String OPEN_LUA_SCRIPT =
            """
                -- 1. 接收execute参数
                local amountKey = KEYS[1] -- 红包余额缓存KEY
                local gradCountKey = KEYS[2] -- 红包剩余可以拆分份额缓存KEY
                local openUsersKey = KEYS[3] -- 红包余额缓存KEY
                local redPacketId = ARGV[1]  -- 红包ID
                local userId = ARGV[2]       -- 拆包ID
                -- 2. 校验是否由拆包资格
                local balanceAmount = tonumber(redis.call('HGET', amountKey, redPacketId)) or 0
                if balanceAmount <= 0
                   return ''
                local gradCount = tonumber(redis.call('HGET', gradCountKey, redPacketId)) or 0
                if gradCount <= 0
                   return ''
                -- 3. 当前剩余可拆分份额为1分，直接返回剩余金额
                if gradCount == 1 then
                   redis.call('HSET', amountKey, redPacketId, 0)
                   redis.call('HSET', gradCountKey, redPacketId, 0)
                   redis.call('SADD', openUsersKey, userId)
                   return tostring(balanceAmount)
                -- 4. 基于二倍均值红包算法，为当前拆包线程随机计算红包金额
                local minAmount = 1
                local avgAmount = math.floor(balanceAmount / gradCount)
                local avgAmount2 = avgAmount * 2
                local openAmount = math.random(minAmount, avgAmount2 + 1)
                   redis.call('HSET', amountKey, redPacketId, balanceAmount - openAmount )
                   redis.call('HSET', gradCountKey, redPacketId, gradCount - 1)
                   redis.call('SADD', openUsersKey, userId)
                   return tostring(openAmount)
            """;

    /**
     * 电商购物车添加
     *
     * 保证用户sku购物车添加与sku对应的店铺购物车信息添加的原子性
     */
    public static final String CACHE_EXPIRE_SKU = "-1";
    public static final String CACHE_EXPIRE_SHOP = "-2";
    public static final String CACHE_EXPIRE_SKU_TOTAL = "-3";
    public static final String CACHE_EXPIRE_ALL = "-4";
    public static final String CACHE_EXIST = "666";
    public static final String CACHE_OK = "1";
    public static final String MALL_ADD_CART_SCRIPT =
            """
              -- 1. 获取缓存KEY
              local userCartSkuKey = KEYS[1]            -- 用户购物车SKU缓存KET（ZSET）
              local userCartShopKey = KEYS[2]           -- 用户购物车店铺缓存KET（ZSET）
              local userCartSkuCountKey = KEYS[3]       -- 用户购物车商品数量缓存KET（HASH）
              local userCartSkuNoneCacheKey = KEYS[4]   -- 用户购物车店铺下SKU空缓存标记KET（String）
              local userCartShopNoneCacheKey = KEYS[5]  -- 用户购物车店铺空缓存标记KET（String）
              local userCartSkuTotalCacheKey = KEYS[6]  -- 用户购物车店收藏SKU商品总量（HASH）
              -- 2. 获取LUA参数
              local skuId = ARGV[1]
              local shopId = ARGV[2]
              local skuCount = ARGV[3]
              local userId = ARGV[4]
              local cartTime = tonumber(ARGV[5])
              -- 3. 校验缓存是否有效
              -- 3.1 校验用户购物车SKU ZSET缓存是否存在
              local skuExistRes = tonumber(redis.call('EXISTS', userCartSkuKey) or '0')
              -- 3.2 校验用户购物车店铺 ZSET缓存是否存在
              local shopExistRes = tonumber(redis.call('EXISTS', userCartShopKey) or '0')
              -- 3.3 校验用户购物车SKU收藏总量缓存是否失效
              local userCartSkuTotalExistRes = tonumber(redis.call('HEXISTS', userCartSkuTotalCacheKey, userId) or '0')
              -- 3.4 校验用户购物车店铺下SKU是否空数据
              local skuNoneCacheExistRes = tonumber(redis.call('EXISTS', userCartSkuNoneCacheKey) or '0')
              -- 3.5 校验用户购物车店铺下店铺是否空数据
              local shopNoneCacheExistRes = tonumber(redis.call('EXISTS', userCartShopNoneCacheKey) or '0')
              -- 4. 店铺&SKU缓存均失效则返回-3重新刷新
              -- 4.1 店铺&SKU缓存均失效则返回-3重新刷新
              if skuExistRes == 0 and skuNoneCacheExistRes == 0 and shopExistRes == 0 and shopNoneCacheExistRes == 0 and userCartSkuTotalExistRes == 0 then
                 return '-4'
              end
              -- 4.2 SKU缓存失效则返回-1重新刷新
              if skuExistRes == 0 and skuNoneCacheExistRes == 0 then
                 return '-1'
              end
              -- 4.3 店铺缓存失效则返回-2重新刷新
              if shopExistRes == 0 and shopNoneCacheExistRes == 0 then
                 return '-2'
              end
              -- 4.3 购物车用户sku收藏总量缓存失效
              if userCartSkuTotalExistRes == 0 then
                 return '-3'
              end
              -- 5. 幂等性保障，避免重复加入购物车
              local score = tonumber(redis.call('ZSCORE', userCartSkuKey, skuId) or '0')
              if score > 0 then
                 return '666'
              end
              -- 6. 添加缓存
              redis.call('ZADD', userCartSkuKey, cartTime, skuId)
              redis.call('ZADD', userCartShopKey, cartTime, shopId)
              redis.call('HSET', userCartSkuCountKey, skuId, skuCount)
              redis.call('HINCRBY', userCartSkuTotalCacheKey, userId, 1)
              return '1'
            """;


    /**
     * 删除购物车缓存
     *
     */
    public static final String MALL_REMOVE_CART_SCRIPT =
            """
              -- 取参数
              local userCartSkuKey = KEYS[1]      -- 用户购物车商品列表缓存KEY -- ZSET
              local userCartShopKey = KEYS[2]     -- 用户购物车商品对应店铺列表缓存KEY -- ZSET
              local userCartSkuCountKey = KEYS[3] -- 用户购物车商品收藏数据缓存KEY -- HASH
              local userCartSkuTotalCacheKey = KEYS[4]  -- 用户购物车店收藏SKU商品总量（HASH）
              local skuId = ARGV[1]               -- 购物车添加sku
              local shopId = ARGV[2]              -- 店铺id
              local userId = ARGV[3]              -- 店铺id
              -- 1. 删除用户店铺下商品收藏数据
              redis.call('ZREM', userCartSkuKey, skuId)
              redis.call('HDEL', userCartSkuCountKey, skuId)
              redis.call('HINCRBY', userCartSkuTotalCacheKey, userId, -1)
              -- 2. 直接添加商品店铺列表缓存
              local skuIsEmpty = tonumber(redis.call('ZCARD', userCartSkuKey) or '0') 
              if skuIsEmpty == 0 then 
                  redis.call('ZREM', userCartShopKey, shopId)
              end 
              -- 删除成功返回 1
              return '1'  
            """;

    /**
     * 延迟队列消息消费
     */
    public static final String REDIS_DELAY_QUEUE_MESSAGE_CONSUME =
            """
              local queueKey = KEYS[1]             -- 队列
              local startScore = tonumber(ARGV[1]) -- 开始score
              local endScore = tonumber(ARGV[2])   -- 结束score
              local messages = redis.call('ZRANGEBYSCORE', queueKey, startScore, endScore)
              if #messages > 0 then
                redis.call('ZREMRANGEBYSCORE', KEYS[1], startScore, endScore)
              end
              return messages
            """;
}
